// Code file original author: Martin Lapierre, http://devinstinct.com

using System;
using Microsoft.Practices.EnterpriseLibrary.Validation.Validators;
using Microsoft.Practices.EnterpriseLibrary.Validation;

namespace EntLibContrib.Validation.Validators
{
    /// <summary>
    /// Describes a <see cref="CollectionCountValidator"/>.
    /// </summary>
    /// Spin-off of the StringLengthValidatorAttribute class.
    /// </remarks>
    [AttributeUsage(AttributeTargets.Property
        | AttributeTargets.Field
        | AttributeTargets.Method
        | AttributeTargets.Parameter,
        AllowMultiple = true,
        Inherited = false)]
    public sealed class CollectionCountValidatorAttribute : ValueValidatorAttribute
    {
        private int lowerBound;
        private RangeBoundaryType lowerBoundType;
        private int upperBound;
        private RangeBoundaryType upperBoundType;

        /// <summary>
        /// <para>Initializes a new instance of the <see cref="CollectionCountValidatorAttribute"/> class with an upper bound constraint.</para>
        /// </summary>
        /// <param name="upperBound">The upper bound.</param>
        public CollectionCountValidatorAttribute(int upperBound)
            : this(0, RangeBoundaryType.Ignore, upperBound, RangeBoundaryType.Inclusive)
        { }

        /// <summary>
        /// <para>Initializes a new instance of the <see cref="CollectionCountValidatorAttribute"/> class with lower and 
        /// upper bound constraints.</para>
        /// </summary>
        /// <param name="lowerBound">The lower bound.</param>
        /// <param name="upperBound">The upper bound.</param>
        public CollectionCountValidatorAttribute(int lowerBound, int upperBound)
            : this(lowerBound, RangeBoundaryType.Inclusive, upperBound, RangeBoundaryType.Inclusive)
        { }

        /// <summary>
        /// <para>Initializes a new instance of the <see cref="CollectionCountValidatorAttribute"/> class with fully specified
        /// bound constraints.</para>
        /// </summary>
        /// <param name="lowerBound">The lower bound.</param>
        /// <param name="lowerBoundType">The indication of how to perform the lower bound check.</param>
        /// <param name="upperBound">The upper bound.</param>
        /// <param name="upperBoundType">The indication of how to perform the upper bound check.</param>
        /// <seealso cref="RangeBoundaryType"/>
        public CollectionCountValidatorAttribute(int lowerBound,
            RangeBoundaryType lowerBoundType,
            int upperBound,
            RangeBoundaryType upperBoundType)
        {
            this.lowerBound = lowerBound;
            this.lowerBoundType = lowerBoundType;
            this.upperBound = upperBound;
            this.upperBoundType = upperBoundType;
        }

        /// <summary>
        /// Creates the <see cref="CollectionCountValidator"/> described by the configuration object.
        /// </summary>
        /// <param name="targetType">The type of object that will be validated by the validator.</param>
        /// <returns>The created <see cref="Validator"/>.</returns>
        protected override Validator DoCreateValidator(Type targetType)
        {
            return new CollectionCountValidator(this.lowerBound,
                this.lowerBoundType,
                this.upperBound,
                this.upperBoundType,
                Negated);
        }
    }
}